﻿using System.IO;
using MetaMapics.Pbf;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTest_MetaMapics.Pbf
{
  [TestClass]
  public class UnitTest_PbfHelper
  {
    [TestMethod]
    public void TestLongCast()
    {
      long[] values = { 0, -1, 1, 1234, -1234, long.MaxValue, long.MinValue };
      foreach (var value in values)
      {
        ulong intermediate = (ulong)value;
        long result = (long)intermediate;
        Assert.AreEqual(value, result);
      }
    }

    [TestMethod]
    public void TestUlongCast()
    {
      ulong[] values = { 0, 1, 1234, 18446744073709551614, ulong.MaxValue, ulong.MinValue };
      foreach (var value in values)
      {
        long intermediate = (long)value;
        ulong result = (ulong)intermediate;
        Assert.AreEqual(value, result);
      }
    }

    [TestMethod]
    public void TestVarint()
    {
      int[] values = { 0, -1, 1, 1234, -2, -1234, int.MaxValue, int.MinValue };
      using (var stream = new MemoryStream())
      {
        for (int i = 0; i < values.Length; i++)
          for (int j = 0; j < 3; j++)
            PbfHelper.WriteVarint(stream, values[i]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < values.Length; i++)
        {
          int bytesRead;
          int result1 = (int)PbfHelper.ReadVarint(stream);
          int result2 = (int)PbfHelper.ReadVarint(stream, out bytesRead);
          uint result3;
          bool success = PbfHelper.TryReadVarint(stream,out result3);
          Assert.AreEqual(values[i], result1);
          Assert.AreEqual(values[i], result2);
          Assert.AreEqual(values[i], (int)result3);
        }
      }
    }

    [TestMethod]
    public void TestLongVarint()
    {
      long[] values = { 0, -1, 1, 1234, -2, -1234, long.MaxValue, long.MinValue };
      using (var stream = new MemoryStream())
      {
        for (int i=0; i<values.Length; i++)
          for (int j = 0; j < 2; j++)
            PbfHelper.WriteVarint(stream, values[i]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i=0; i<values.Length; i++)
        {
          int bytesRead;
          long result1 = (long)PbfHelper.ReadLongVarint(stream);
          long result2 = (long)PbfHelper.ReadLongVarint(stream, out bytesRead);
          Assert.AreEqual(values[i], result1);
          Assert.AreEqual(values[i], result2);
        }
      }
    }

    [TestMethod]
    public void TestUlongVarint()
    {
      ulong[] values = { 0, 1, 1234, 18446744073709550382, ulong.MaxValue, ulong.MinValue };
      using (var stream = new MemoryStream())
      {
        foreach (var value in values)
          PbfHelper.WriteVarint(stream, value);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < values.Length; i++)
        {
          ulong result = PbfHelper.ReadLongVarint(stream);
          Assert.AreEqual(values[i], result);
        }
      }
    }

    [TestMethod]
    public void TestLongBits64()
    {
      long[] values = { 0, -1, 1, 1234, -2, -1234, long.MaxValue, long.MinValue };
      using (var stream = new MemoryStream())
      {
        for (int i = 0; i < values.Length; i++)
          PbfHelper.WriteBits64(stream, values[i]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < values.Length; i++)
        {
          long result = PbfHelper.ReadBits64(stream);
          Assert.AreEqual(values[i], result);
        }
      }
    }

    [TestMethod]
    public void TestFloat()
    {
      float[] values = { 0, -1, 1, 1234, -2, -1234, 0.1f, -0.1f, float.MaxValue, float.MinValue, float.Epsilon };
      using (var stream = new MemoryStream())
      {
        for (int i = 0; i < values.Length; i++)
          PbfHelper.WriteFloat(stream, values[i]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < values.Length; i++)
        {
          float result = PbfHelper.ReadFloat(stream);
          Assert.AreEqual(values[i], result);
        }
      }
    }

    [TestMethod]
    public void TestDouble()
    {
      double[] values = { 0, -1, 1, 1234, -2, -1234, 0.1, -0.1, double.MaxValue, double.MinValue, double.Epsilon };
      using (var stream = new MemoryStream())
      {
        for (int i = 0; i < values.Length; i++)
          PbfHelper.WriteDouble(stream, values[i]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < values.Length; i++)
        {
          double result = PbfHelper.ReadDouble(stream);
          Assert.AreEqual(values[i], result);
        }
      }
    }

    [TestMethod]
    public void TestBool()
    {
      bool[] values = { true, false };
      using (var stream = new MemoryStream())
      {
        for (int i = 0; i < values.Length; i++)
          PbfHelper.WriteBool(stream, values[i]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < values.Length; i++)
        {
          bool result = PbfHelper.ReadBool(stream);
          Assert.AreEqual(values[i], result);
        }
      }
    }

    [TestMethod]
    public void TestTag()
    {
      PbfWireType[] wireTypes = { PbfWireType.Bits32, PbfWireType.Bits64, PbfWireType.LengthDelimited, PbfWireType.VarInt };
      uint[] fieldNums = { 1, 2, 1234, PbfHelper.MaxFieldNum };
      using (var stream = new MemoryStream())
      {
        for (int i = 0; i < fieldNums.Length; i++)
          for (int j = 0; j < wireTypes.Length; j++)
            PbfHelper.WriteTag(stream, fieldNums[i], wireTypes[j]);
        stream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < fieldNums.Length; i++)
          for (int j = 0; j < wireTypes.Length; j++)
        {
          PbfWireType wireType;
          uint fieldNum = PbfHelper.ReadTag(stream, out wireType);
          Assert.AreEqual(fieldNums[i], fieldNum);
          Assert.AreEqual(wireTypes[j], wireType);
        }
      }
    }

    [TestMethod]
    public void TestZigZagInt()
    {
      int[] values = { 0, -1, 1, 1234, -2, -1234, int.MaxValue, int.MinValue };
      for (int i = 0; i < values.Length; i++)
      {
        int result = PbfHelper.DecodeZigZag(PbfHelper.EncodeZigZag(values[i]));
        Assert.AreEqual(values[i], result);
        result = PbfHelper.EncodeZigZag(PbfHelper.DecodeZigZag(values[i]));
        Assert.AreEqual(values[i], result);
      }
    }

    [TestMethod]
    public void TestZigZagLong()
    {
      long[] values = { 0, -1, 1, 1234, -1234, long.MaxValue, long.MinValue };
      for (int i = 0; i < values.Length; i++)
      {
        long result = PbfHelper.DecodeZigZag(PbfHelper.EncodeZigZag(values[i]));
        Assert.AreEqual(values[i], result);
        result = PbfHelper.EncodeZigZag(PbfHelper.DecodeZigZag(values[i]));
        Assert.AreEqual(values[i], result);
      }
    }
  }
}
